package com.fitzframework.inject;

import com.fitzframework.core.BeanContainer;
import com.fitzframework.inject.annotation.Autowired;
import com.fitzframework.util.ClassUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Set;

@Slf4j
public class DependencyInjector {

    private BeanContainer beanContainer;

    public DependencyInjector() {
        beanContainer = BeanContainer.getInstance();
    }

    /**
     * 依赖注入
     */
    public void inject(){
        //1.遍历容器中所有的class对象
        if (CollectionUtils.isEmpty(beanContainer.getClasses())){
            log.warn("容器中没有任何bean");
            return;
        }
        for (Class<?> clazz : beanContainer.getClasses()){
            Field[] fields = clazz.getDeclaredFields();
            if (CollectionUtils.isEmpty(Arrays.asList(fields))){
                log.warn("该class对象没有任何属性:{}",clazz.getSimpleName());
                continue;
            }
            //遍历对象的成员变量
            for (Field field : fields){
                //找出被Autowired标记的成员变量
                if (field.isAnnotationPresent(Autowired.class)||field.isAnnotationPresent(Resource.class)){
                    String nameValue = getFieldAnnotationName(field);
                    //获取成员变量的类型
                    Class<?> fieldClass = field.getType();
                    Object fieldValue = getFieldInstance(fieldClass,nameValue);
                    if (fieldValue == null){
                        log.error("无法注入该属性:{}",fieldClass.getSimpleName());
                        throw new RuntimeException("无法注入该属性:"+fieldClass.getName());
                    }else {
                        //获取成员变量在容器里对应的实例
                        Object targetBean = beanContainer.getBean(clazz);
                        //通过反射将对应的成员变量实例注入到成员变量所在的实例
                        if (targetBean != null){
                            ClassUtil.setField(field,targetBean,fieldValue,true);
                        }
                    }
                }
            }
        }
    }

    /**
     *
     * @param fieldClass
     * @return
     */
    private Object getFieldInstance(Class<?> fieldClass,String nameValue) {
        Object fieldValue = beanContainer.getBean(fieldClass);
        if (fieldValue != null){
            return fieldValue;
        }
        Class<?> implementedClass = getImplementedClass(fieldClass,nameValue);
        if (implementedClass != null){
            return beanContainer.getBean(implementedClass);
        }
        return null;
    }

    /**
     * 获取接口的实现类
     * @param fieldClass
     * @param nameValue
     * @return
     */
    private Class<?> getImplementedClass(Class<?> fieldClass,String nameValue) {
        Set<Class<?>> classSet = beanContainer.getClassesBySuper(fieldClass);
        if (CollectionUtils.isNotEmpty(classSet)){
            if (StringUtils.isBlank(nameValue)){
                if (classSet.size() == 1){
                    return classSet.iterator().next();
                }else {
                    log.error("找到多个实现类，请在@Autowired或@Resource上指定name属性");
                    throw new RuntimeException("找到多个实现类，请在@Autowired或@Resource上指定name属性:"+fieldClass.getName());
                }
            }else {
                for (Class<?> clazz : classSet){
                    if (nameValue.equals(clazz.getSimpleName())){
                        return clazz;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 获取注解上的name
     * @param field
     * @return
     */
    private String getFieldAnnotationName(Field field){
       if (field.isAnnotationPresent(Autowired.class)){
           Autowired autowired = field.getAnnotation(Autowired.class);
           return autowired.name();
       }
       Resource resource = field.getAnnotation(Resource.class);
       return resource.name();
    }
}
